Venn Diagrams show, conceptually, how sets or ideas overlap.
Euler Diagrams only show observed relationships.
Area-proportional Euler Diagrams show approximately show relative size
Degrees-of-freedom issue:
With 3 sets, power set is 2n=8, but only have 3⋅(n−1)=6 degrees of freedom.
Optimization Problem:
Wilkinson (2012) -- R/Java app for optimizing circles
Julia package for drawing area-proportional Euler diagrams
https://github.com/HarlanH/VennEuler.jl
Features:
Limitations:
In [3]:
# packages to get JSON data from an HTTP API
using Requests
using JSON
In [4]:
# no, I'm not providing my Meetup API key -- get your own!
apikey = open(readchomp, "apikey");
apikey[1:5]
Out[4]:
In [5]:
# ask the Meetup API for deets about a group
function getGroupInfo(apikey, urlname)
request = "https://api.meetup.com/2/groups?key=$apikey&sign=true&group_urlname=$urlname"
ret = get(request)
dat = JSON.parse(ret.data)
dat["results"][1]
end
gi = getGroupInfo(apikey, "TrackMaven-Monthly-Challenge")
Out[5]:
In [6]:
# ask the Meetup API for Member IDs from a group
# requires chunked requests (a better way would be to use the "next" field in the response)
function getMembers(apikey, group_id, memberCt; verbose=true)
chunksize = 200
memberIds = Array(Int,0)
if verbose print(group_id) end
for page in 0:ifloor(memberCt/chunksize)
request = "https://api.meetup.com/2/members?key=$apikey&sign=true&group_id=$group_id&page=$chunksize&offset=$page&only=id"
ret = get(request)
dat = JSON.parse(ret.data)
if verbose print('.') end
for x in dat["results"]
push!(memberIds, x["id"])
end
end
if verbose println() end
memberIds
end
member_ids = getMembers(apikey, gi["id"], gi["members"])
member_ids[1:20]
Out[6]:
In [7]:
# great, seems to work, now get all the members for relevant Meetups, storing as a dict of sets
group_names = ["stats-prog-dc", "Data-Visualization-DC",
"DC-Hack-and-Tell", "TrackMaven-Monthly-Challenge", "hack-edu"]
group_members_struct = Dict()
for grname in group_names
gi = getGroupInfo(apikey, grname)
group_members_struct[grname] =
Set(getMembers(apikey, gi["id"], gi["members"])...)
end
group_members_struct
# takes a couple minutes -- jump to the end!
Out[7]:
In [8]:
# then convert that dict of sets to a bool matrix
everyone = union([v for (k,v) in group_members_struct]...)
memb_group = [in(memb, group_members_struct[group])
for memb in everyone, group in group_names]
Out[8]:
In [9]:
# and now we're good to make a VennEuler diagram!
using VennEuler
In [14]:
eo = make_euler_object(group_names,
memb_group,
EulerSpec(:circle), # rectangles > circles!
sizesum=.3) # scaling in unit square
(minf,minx,ret) = optimize_iteratively( # greedy meta-optimization algorithm
eo, # problem we're trying to solve
random_state(eo), # where to start
ftol=-1, xtol=0.0025, maxtime=5, pop=100) # quick 'n dirty
(minf,minx,ret) = optimize(eo, # global optimization
minx, # start where we left off
ftol=.00005, xtol=0.001, maxtime=40, pop=250) # more horsepower this time...
println("FINALLY:\ngot $minf at $minx (returned $ret)")
In [15]:
render("circles1.svg", eo, minx)
In [24]:
# fancier shapes
eo = make_euler_object(group_names,
memb_group,
[EulerSpec(:circle), EulerSpec(:square, [.5, .5], [0, 0]), EulerSpec(:triangle),
EulerSpec(:rectangle), EulerSpec(:rectangle)],
sizesum=.3) # scaling in unit square
(minf,minx,ret) = optimize_iteratively( # greedy meta-optimization algorithm
eo, # problem we're trying to solve
random_state(eo), # where to start
ftol=-1, xtol=0.0025, maxtime=5, pop=100) # quick 'n dirty
(minf,minx,ret) = optimize_iteratively( # greedy meta-optimization algorithm
eo, # problem we're trying to solve
minx, # start where we left off
ftol=-1, xtol=0.0025, maxtime=5, pop=100) # quick 'n dirty
(minf,minx,ret) = optimize(eo, # global optimization
minx, # start where we left off
ftol=.000005, xtol=0.001, maxtime=40, pop=300) # more horsepower this time...
println("FINALLY:\ngot $minf at $minx (returned $ret)")
In [25]:
render("multi4.svg", eo, minx)